package com.zzyl.nursing.service.impl;

import java.sql.Array;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;

import java.time.format.DateTimeFormatter;
import java.util.*;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.zzyl.common.constant.CacheConstants;
import com.zzyl.common.utils.DateUtils;
import com.zzyl.common.utils.StringUtils;
import com.zzyl.framework.web.service.TokenService;
import com.zzyl.nursing.domain.Device;
import com.zzyl.nursing.domain.DeviceData;
import com.zzyl.nursing.dto.QueryDeviceDataByDay;
import com.zzyl.nursing.dto.QueryDevicePropertyStatusDto;
import com.zzyl.nursing.dto.UserLoginRequestDto;
import com.zzyl.nursing.mapper.DeviceDataMapper;
import com.zzyl.nursing.service.IDeviceDataService;
import com.zzyl.nursing.service.IDeviceService;
import com.zzyl.nursing.service.LoginService;
import com.zzyl.nursing.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import com.zzyl.nursing.mapper.FamilyMemberMapper;
import com.zzyl.nursing.domain.FamilyMember;
import com.zzyl.nursing.service.IFamilyMemberService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;



/**
 * 老人家属Service业务层处理
 *
 * @author ruoyi
 * @date 2025-07-31
 */
@Service
@Slf4j
public class FamilyMemberServiceImpl extends ServiceImpl<FamilyMemberMapper, FamilyMember> implements IFamilyMemberService {
    @Autowired
    private FamilyMemberMapper familyMemberMapper;
    @Autowired
    private LoginService loginService;
    @Autowired
    private TokenService tokenService;
    @Autowired
    private IDeviceDataService deviceDataService;
    @Autowired
    private IDeviceService deviceService;
    @Autowired
    private RedisTemplate redisTemplate;


    static List<String> DEFAULT_NICKNAME_PREFIX = ListUtil.of("生活更美好",
            "大桔大利",
            "日富一日",
            "好柿开花",
            "柿柿如意",
            "一椰暴富",
            "大柚所为",
            "杨梅吐气",
            "天生荔枝"
    );

    @Override
    public LoginVo login(UserLoginRequestDto userLoginRequestDto) {
        //1.查询用户openId
        String openId = loginService.getOpenId(userLoginRequestDto.getCode());
        //2.根据openId查询用户
        FamilyMember familyMember = getOne(Wrappers.<FamilyMember>lambdaQuery().eq(FamilyMember::getOpenId, openId));

        //3.查询手机号
        String phone = loginService.getPhone(userLoginRequestDto.getPhoneCode());

        // 如果用户不存在，则创建新用户
        if (ObjectUtil.isEmpty(familyMember)) {
            familyMember = FamilyMember.builder().openId(openId).build();
            // 新用户直接设置手机号和昵称并保存
            familyMember.setPhone(phone);
            String nickName = DEFAULT_NICKNAME_PREFIX.get((int) (Math.random() * DEFAULT_NICKNAME_PREFIX.size()))
                    + StringUtils.substring(familyMember.getPhone(), 7);
            familyMember.setName(nickName);
            save(familyMember); // 保存新用户
        } else {
            // 已存在用户，调用更新或保存方法
            familyMember = updateOrSave(familyMember, phone);
        }

        //4.创建令牌
        Map<String, Object> claims = new HashMap<>();
        claims.put("userId", familyMember.getId());
        claims.put("nickName", familyMember.getName());
        String token = tokenService.createToken(claims);
        //5.封装数据
        LoginVo loginVo = new LoginVo();
        loginVo.setToken(token);
        loginVo.setNickName(familyMember.getName());
        return loginVo;
    }

    /**
     * 新增或者更新用户
     *
     * @param familyMember
     * @param phone
     */
    private FamilyMember updateOrSave(FamilyMember familyMember, String phone) {
        // 定义一个标记
        boolean needUpdate = false;
        if (ObjectUtil.notEqual(familyMember.getPhone(), phone)) {
            // 如果手机号不一致，则更新手机号
            needUpdate = true;
            familyMember.setPhone(phone);
            // 更新昵称
            String nickName = DEFAULT_NICKNAME_PREFIX.get((int) (Math.random() * DEFAULT_NICKNAME_PREFIX.size()))
                    + StringUtils.substring(familyMember.getPhone(), 7);
            familyMember.setName(nickName);
        }
        // 更新用户当用户登录的时候如果手机号不一致，则更新手机号 如果一致，则不更新
        if (needUpdate) {
            updateById(familyMember);
        }
        return familyMember;
    }


    /**
     * 查询老人家属
     *
     * @param id 老人家属主键
     * @return 老人家属
     */
    @Override
    public FamilyMember selectFamilyMemberById(Long id) {
        return getById(id);
    }

    /**
     * 查询老人家属列表
     *
     * @param familyMember 老人家属
     * @return 老人家属
     */
    @Override
    public List<FamilyMember> selectFamilyMemberList(FamilyMember familyMember) {
        return familyMemberMapper.selectFamilyMemberList(familyMember);
    }

    /**
     * 新增老人家属
     *
     * @param familyMember 老人家属
     * @return 结果
     */
    @Override
    public int insertFamilyMember(FamilyMember familyMember) {
        return save(familyMember) ? 1 : 0;
    }

    /**
     * 修改老人家属
     *
     * @param familyMember 老人家属
     * @return 结果
     */
    @Override
    public int updateFamilyMember(FamilyMember familyMember) {
        return updateById(familyMember) ? 1 : 0;
    }

    /**
     * 批量删除老人家属
     *
     * @param ids 需要删除的老人家属主键
     * @return 结果
     */
    @Override
    public int deleteFamilyMemberByIds(Long[] ids) {
        return removeByIds(Arrays.asList(ids)) ? 1 : 0;
    }

    /**
     * 删除老人家属信息
     *
     * @param id 老人家属主键
     * @return 结果
     */
    @Override
    public int deleteFamilyMemberById(Long id) {
        return removeById(id) ? 1 : 0;
    }

    /**
     * 查询设备属性状态
     *
     * @param dto
     */
    @Override
    public QueryDevicePropertyStatusObject queryDevicePropertyStatus(QueryDevicePropertyStatusDto dto) {
        //根据设备名称和产品key查询设备id
        Device device = deviceService.getOne(Wrappers.<Device>lambdaQuery().eq(Device::getDeviceName, dto.getDeviceName())
                .eq(Device::getProductKey, dto.getProductKey()));
        if (ObjectUtil.isEmpty(device)) {
            throw new RuntimeException("数据不存在");
        }
        String iotId = device.getIotId();
        //根据设备iotid查询设备数据
//        List<DeviceData> list = deviceDataService.list(Wrappers.<DeviceData>lambdaQuery().eq(DeviceData::getIotId, iotId));
        //在redis中查询最新的数据
        String deviceDataStr = (String) redisTemplate.opsForHash().get(CacheConstants.IOT_DEVICE_LAST_DATA, iotId);
        if (ObjectUtil.isEmpty(deviceDataStr)) {
            throw new RuntimeException("设备数据不存在");
        }
        List<DeviceData> list = JSONUtil.toList(deviceDataStr, DeviceData.class);
        //数据存在
        List<PropertyStatusInfo> propertyStatusInfoList = new ArrayList<>();
        for (DeviceData deviceData : list) {

            Instant instant = deviceData.getAlarmTime().atZone(ZoneId.systemDefault()).toInstant();
            long timestamp = instant.toEpochMilli();
            PropertyStatusInfo propertyStatusInfo = PropertyStatusInfo.builder()
                    .dataType("double")
                    .identifier(deviceData.getFunctionId())
                    .time(String.valueOf(timestamp))
                    .value(deviceData.getDataValue())
                    .name(deviceData.getFunctionId())
                    .build();
            propertyStatusInfoList.add(propertyStatusInfo);

        }
        ListBean listBean = new ListBean(propertyStatusInfoList);
        QueryDevicePropertyStatusObject queryDevicePropertyStatusObject = new QueryDevicePropertyStatusObject(listBean);
        return queryDevicePropertyStatusObject;

    }

    @Override
    public List<Map<String, Object>> queryDeviceDataListByDay(String functionId, Long startTime, Long endTime, String iotId) {
        LocalDateTime startTimeDate = localDateTimeFlormate(startTime);
        log.warn("经过加工之后的时间格式为:{}", startTimeDate);
        LocalDateTime endTimeDate = localDateTimeFlormate(endTime);
        log.warn("经过加工之后的时间格式为:{}", endTimeDate);
        List<DeviceData> deviceDataList = deviceDataService.list(Wrappers.<DeviceData>lambdaQuery()
                .eq(DeviceData::getIotId, iotId)
                .between(DeviceData::getAlarmTime,startTimeDate,endTimeDate)
                .eq(DeviceData::getFunctionId, functionId)
        );
        //遍历数据 --如果是同一个时间段的数据进行求平均值存储到一个map集合中
        List<Map<String, Object>> deviceDataMapList = new ArrayList<>();

        deviceDataList.forEach(deviceData -> {
            //对设备信息的alarmTime进行格式化为 小时:00的格式
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:00");
            String alarmTime = deviceData.getAlarmTime().format(formatter);
            log.info("通过时间格式修改后的字符串为:{}", alarmTime);
            Map<String, Object> map = new HashMap<>();
            map.put("dateTime", alarmTime);
            map.put("dataValue", Double.valueOf(deviceData.getDataValue()));
            deviceDataMapList.add(map);
        });
        //创建新的集合 蒋24个小时的数据全部放入
        List<Map<String, Object>> newList = new ArrayList<>(24);
        for (int i = 0; i <= 23; i++) {
            String tailTime = ":00";
            String time;
            if (i < 10) {
                time = "0" + i + tailTime;
            } else {
                time = i + tailTime;
            }
            //如果数据库中有的数据直接传入
            for (Map<String, Object> map : deviceDataMapList) {
                if (time.equals(map.get("dateTime"))) {
                    newList.add(map);
                    break;
                }
            }
            //没有的数据，则创建添加
            Map<String, Object> map = new HashMap<>();
            map.put("dateTime", time);
            map.put("dataValue", 0.0);
            if (newList.size() != i + 1) {
                newList.add(map);
            }
        }
        return newList;
    }

    @Override
    public List<Map<String, Object>> queryDeviceDataListByWeek(String functionId, Long startTime, Long endTime, String iotId) {
        LocalDateTime startTimeDate = localDateTimeFlormate(startTime);
        log.warn("经过加工之后的时间格式为:{}", startTimeDate);
        LocalDateTime endTimeDate = localDateTimeFlormate(endTime);
        log.warn("经过加工之后的时间格式为:{}", endTimeDate);
        List<DeviceData> deviceDataList = deviceDataService.list(Wrappers.<DeviceData>lambdaQuery()
                .eq(DeviceData::getIotId, iotId)
                .between(DeviceData::getAlarmTime,startTimeDate,endTimeDate)
                .eq(DeviceData::getFunctionId, functionId)
        );
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM.dd");
        List<Map<String, Object>> deviceDataMapList = new ArrayList<>();
        deviceDataList.forEach(deviceData -> {
            //对设备信息的alarmTime进行格式化为 小时:00的格式
            String alarmTime = deviceData.getAlarmTime().format(formatter);
            log.info("通过时间格式修改后的字符串为:{}", alarmTime);
            HashMap<String, Object> map = new HashMap<>();
            map.put("dateTime", alarmTime);
            map.put("dataValue", Double.valueOf(deviceData.getDataValue()));
            deviceDataMapList.add(map);
        });
        List<Map<String, Object>> newList = new ArrayList<>(7);
        for (int i = 0; i < 7; i++){
            String dataTime=startTimeDate.format(formatter);
            for (Map<String, Object> stringObjectMap : deviceDataMapList) {
                if (stringObjectMap.get("dateTime").equals(dataTime)){
                    newList.add(stringObjectMap);
                    break;
                }
            }
            //如果查询数据库的数据没有则填充0 设置对应的日期
            if (newList.size() != i + 1) {
                Map<String, Object> map = new HashMap<>();
                map.put("dateTime", dataTime);
                map.put("dataValue", 0);
                newList.add(map);
            }
            //开始时间加1天
            startTimeDate= startTimeDate.plusDays(1);
        }
        return newList;
    }




    /**
     * 将时间戳转化为LocalDateTime格式
     *
     * @param time
     * @return
     */
    private LocalDateTime localDateTimeFlormate(Long time) {
        return Instant.ofEpochMilli(time)
                .atZone(ZoneId.systemDefault())
                .toLocalDateTime();
    }


}
